<?php

namespace maoxuner\LaravelJsonRpc\Entities;

use Illuminate\Support\Facades\Validator;
use maoxuner\LaravelJsonRpc\Exceptions\ParseException;
use maoxuner\LaravelJsonRpc\Exceptions\RequestException;
use maoxuner\LaravelJsonRpc\Rules\Identifier;

class RequestObject extends EntityObject
{
    public string $jsonrpc = '2.0';

    public string $method;

    public ?array $params = null;

    /**
     * @var string|int|null
     */
    public mixed $id = null;

    /**
     * @throws ParseException|RequestException
     */
    public static function build($data): static
    {
        if (! is_array($data)) {
            throw new ParseException;
        }

        return static::load($data);
    }

    /**
     * @throws RequestException
     * @throws \Illuminate\Validation\ValidationException
     */
    public static function validate(array $data): array
    {
        $validator = Validator::make($data, [
            'jsonrpc' => 'required|string|in:2.0',
            'method' => [
                'required',
                'string',
                function ($attribute, $value, $fail) {
                    if (str_starts_with($value, 'rpc.')) {
                        $fail('The '.$attribute.' value is reserved for rpc-internal methods and extensions.');
                    }
                },
            ],
            'params' => 'array',
            'id' => new Identifier,
        ]);

        if ($validator->fails()) {
            throw RequestException::build($validator->getMessageBag()->getMessages());
        }

        return $validator->validated();
    }

    public function toArray()
    {
        $data = [
            'jsonrpc' => $this->jsonrpc,
            'method' => $this->method,
        ];
        if ($this->params) {
            $data['params'] = $this->params;
        }
        if ($this->id) {
            $data['id'] = $this->id;
        }

        return $data;
    }
}
